:- module(conjunto).
:- use_module(set).
:- comment(summary, "Finite Set Constraints Library - obsolescent, use library(fd_sets) instead").
:- comment(author, "Carmen Gervet and Pascal Brisset, ECRC").
:- comment(copyright, "Imperial College London and ICL").
:- comment(date, "$Date: 2003/06/05 19:36:58 $").
:- comment(status, deprecated).
:- comment(# / 2, [summary : "Var is the cardinality of the set term Sterm.\n\n", template : "#(?Sterm,?Var)", desc : html("   Var is the cardinality of the set term Sterm.  If Sterm is a known set\n   and Var is free, Var is instanciated to the cardinality of Sterm.  If\n   both are known, the predicate checks that Var is the cardinality of\n   Sterm.  If Sterm is a set variable and Var is free, Var becomes a domain\n   variable representing the set term cardinality.  The predicate is\n   delayed and activated as soon as one of the bounds of Sterm or Var is\n   modified.  If Sterm is a set variable and and Var is a domain variable\n   it checks that Var contains the cardinality of Sterm.  It might infer a\n   modification of the bounds of the set domain.\n\n<P>\n"), args : ["?Sterm" : "A set term or a ground set.", "?Var" : "A free variable, a domain variable or an integer."], resat : "   No.", fail_if : "   None.\n\n", eg : "\neclipse 3]: S `:: {}..{c,d}, S1= {1,2,3}, #(S \\/ S1, V).\n\nS = S{{} .. {c, d}}\nS1 = {1, 2, 3}\nV = Card{[3..5]}\n\nDelayed goals:\n        union_s({1, 2, 3}, S{{} .. {c, d}},\n               R{{1, 2, 3} .. {1, 2, 3, c, d}})\n        car_s(R{{1, 2, 3} .. {1, 2, 3, c, d}}, Card{[3..5]})\nyes.\n\n\n\n", see_also : [`:: / 2, `= / 2]]).
:- comment(`:: / 2, [summary : "Terms in Svar have the set domain Domain.\n\n", template : "?Svar `::  +Domain", desc : html("   The main purpose of this predicate is to create set domain variables.\n   Domain has to be a closed set interval specified as Glb..Lub.  If SVar\n   is already a set domain variable, its set domain will be updated\n   according to the new domain; if it is instanciated, the predicate checks\n   is the set value lies in the domain.  If the upper bound equals the\n   lower bound the set variable describes a ground set.  Otherwise, if SVar\n   is a free variable, it is converted to a set domain variable.  If SVar\n   is a list, this will be performed for all its elements.  If Domain is\n   free, it fails.\n\n<P>\n"), args : ["?SVar" : "A set variable or a list of set variables.", "+Domain" : "Lattice specified by its upper and lower bound Glb..Lub such                that Glb is a subset of Lub."], resat : "   No.", fail_if : "   Fails if Domain is free, or if SVar cannot have the domain Domain.\n\n", eg : "\n[eclipse 3]: S `:: {}..{a,{2,3},c}.\n\nS = S{{} .. {a, {2,3}, c}}\nyes.\n\n\n\n", see_also : [glb / 2, lub / 2, set_range / 3, set / 1]]).
:- comment(`< / 2, [summary : "Sterm is a subset of Sterm1.\n\n", template : "?Sterm `< ?Sterm1", desc : html("   This constraint states that the set term Sterm has to be a subset of the\n   set term Sterm1.  If both terms are known sets, this constraint checks\n   the inclusion.  If either Sterm or Sterm1 is a known set, this\n   constraint checks the inclusion and the unconsistent bounds of the set\n   variables involved are modified.  If both terms contain set variables\n   their domain bounds are checked and the constraint is delayed.  It is\n   activated as soon as the upper bound of Sterm1 or the lower bound of\n   Sterm is modified.\n\n<P>\n"), args : ["?Sterm" : "A set term.", "?Sterm1" : "A set term."], resat : "   No.", fail_if : "   Fails if Sterm can not be a subset of Sterm1.\n\n", eg : "\n[eclipse 3]: S `:: {1}.. {1,2,3,4}, S1 `:: {} .. {1,2,3},\n S `< S1.\n\nS1 = S1{{1} .. {1, 2, 3}}\nS = S{{1} .. {1, 2, 3}}\n\nDelayed goals:\n       S1{{1} .. {1, 2, 3}} sub_s S{{1} .. {1, 2, 3}}\nyes.\n\n\n\n", see_also : [`:: / 2]]).
:- comment(`<> / 2, [summary : "Sterm and Sterm1 are disjoint.\n\n", template : "?Sterm `<> ?Sterm1", desc : html("   This constraint states that the set terms Sterm and Sterm1 have to be\n   disjoint.  If both terms are known sets, it checks the empty\n   intersection between them.  If either Sterm or Sterm1 is a known set,\n   this constraint checks the empty intersection or disjointness and the\n   unconsistent bounds of the set variables involved are modified.  If both\n   terms contain set variables, the consistency of the domain bounds is\n   checked and the constraint is delayed.  It is activated as soos as the\n   lower bound of one set variable involved is modified.\n\n<P>\n"), args : ["?Sterm" : "A set term.", "?Sterm1" : "A set term."], resat : "   No.", fail_if : "   Fails if Sterm can not be a subset of Sterm1.\n\n", eg : "\n[eclipse 3]: S `:: {}.. {1,2,3},S1 `:: {1} .. {1,2,3,4},\n             S `<> S1.\n\nS = S{{} .. {2, 3}}\nS1 = S1{{1} .. {1, 2, 3, 4}}\n\nDelayed goals:\n        S{{} .. {2, 3}} dis_s S1{{1} .. {1, 2, 3, 4}}\nyes.\n\n\n\n", see_also : [`:: / 2]]).
:- comment(`= / 2, [summary : "Sterm and Sterm1 are equal.\n\n", template : "?Sterm `= ?Sterm1", desc : html("   This constraint states that the two set terms are equal.  It is\n   activated whenever the upper or the lower bound of a set domain variable\n   is updated.  When propagating set domain updates, the system reasons\n   only over the upper and lower bound sets of values of the set domain and\n   makes sure that these sets of values are consistent with those of other\n   set domain variables.\n\n<P>\n   If this constraint is not solved, this predicate delays until it can be\n   completely solved.\n\n<P>\n"), args : ["?Sterm" : "A ground set, a set domain variable or a set expression                containing set operators (union \\/, intersection /\\,                difference \\).", "?Sterm1" : "A ground set, a set domain variable or a set expression."], resat : "   No.", fail_if : "   Fails if the two set terms have a different set value.\n\n", eg : "\n[eclipse 2]: S `:: {}.. {1,2,3}, [S1,S2] `:: {}..{3,4,5},\n             S \\/  S1 `= S2.\n\nS = S{{} .. {3}}\nS1 = S1{{} .. {3, 4, 5}}\nS2 = S2{{} .. {3, 4, 5}}\n\nDelayed goals:\n        union_s(S{{} .. {3}}, S1{{} .. {3, 4, 5}},\nS2{{} .. {3, 4, 5}})\nyes.\n\n\n\n", see_also : [`:: / 2]]).
:- comment(all_disjoint / 1, [summary : "Lsets is a list of set domain variables which are constrained to be\npairwise disjoint.\n\n", template : "all_disjoint(?Lsets)", desc : html("   Lsets is a list of set domain variables which are constrained to be\n   pairwise disjoint.  Once the unconsistent domain bounds have been\n   updated.  The predicate is a programming abstraction standing for\n   conjunction of disjointness constraints.  The generated disjointness\n   constraints are delayed.  They are activated each time a lower bound of\n   one set domain involed is modified.\n\n<P>\n"), args : ["?Lsets" : "List of set domain variables."], resat : "   No.", fail_if : "   Fails if some elements of Lsets are not set variables or if all the set\n   variables can not be pairwise disjoint.\n\n", eg : "\nS `:: {}.. {1,3,5}, S1 `:: {1} .. {1,3,4}, S2 `::{3,4}..{3,4,5},\nall_disjoint([S,S1,S2]).\n\nS = S{{} .. {5}}\nS1 = {1}\nS2 = S2{{3, 4} .. {3, 4, 5}}\n\nDelayed goals:\n        S{{} .. {5}} dis_s S2{{3, 4} .. {3, 4, 5}}\nyes.\n", see_also : [`:: / 2, `<> / 2, `= / 2, all_union / 2]]).
:- comment(all_union / 2, [summary : "Lsets is a list of set domain variables whose union is the set term Svar.\n\n", template : "all_union(?Lsets, ?Svar)", desc : html("   Svar is the union of all the set variables appearing in Lsets.  If Svar\n   is a free variable, it becomes a set variable and its attached domain is\n   defined from the union of the domains or known sets appearing in Lsets.\n\n<P>\n"), args : ["?Lsets" : "A list of set domain variables.", "?Svar" : "A free variable or a set variable."], resat : "   No.", fail_if : "   Fails if some elements of Lsets are not set variables and if Svar can\n   not be the union of the Lsets elements.\n\n", eg : "\n[eclipse 13]: S `:: {}.. {1,2,3,5}, S1 `:: {1} .. {1,2,3,4},\nall_union([S, S1],{1,2,3,4,5}).\n\nS = S{{5} .. {1, 2, 3, 5}}\nS1 = S1{{1, 4} .. {1, 2, 3, 4}}\n\nDelayed goals:\n        ground_union(S{{5} .. {1, 2, 3, 5}},\nS1{{1, 4} .. {1, 2, 3, 4}}, {1, 2, 3, 4, 5})\nyes.\n\n\n\n", see_also : [`:: / 2, `= / 2, `<> / 2, all_disjoint / 1]]).
:- comment(el_weight / 2, [summary : "Var is an element of type e(Val,Weight) from a weighted domain.  Wvar is a\nfree variable unifying with the weight Weight of Var.\n\n", template : "el_weight(+Var, ?Wvar)", desc : html("   Unifyes the weight of the term Var which should be of the form\n   e(Val,Weight) with Wvar.  This predicate is convenient to select\n   elements for the labeling of weighted sets.\n\n<P>\n"), args : ["+Var" : "A weighted element.", "?Wvar" : "Term unifying with an integer."], resat : "   No.", fail_if : "   Fails if Var is not of the form e(Val,Weight) or if Wvar is not\n   unifyable with the weight.\n\n", eg : "\n[eclipse 12]: E = e(1,2), el_weight(E, W).\n\nE = e(1, 2)\nW = 2\nyes.\n\n\n\n", see_also : [max_weight / 2, `:: / 2]]).
:- comment(glb / 2, [summary : "S is a set domain variable and Glb is the lower bound of its domain.\n\n", template : "glb(?S, ?Glb)", desc : html("   Glb is the ground set corresponding to the lower bound of the domain of\n   S. If Glb is a free variable, it is instanciated to the lower bound of\n   the domain of S. If it is a ground set, it should be equal to the lower\n   bound of the domain of S, otherwise it fails.\n\n<P>\n"), args : ["?S" : "A set domain variable.", "?Glb" : "A free variable or a ground set."], resat : "   No.", fail_if : "   Fails if S is not a set domain variable or if Glb is a ground set not\n   equal to the lower bound of S domain.\n\n", eg : "\n[eclipse 9]: S `:: {}.. {1,2,3,5}, glb(S,Glb).\n\nS = S{{} .. {1, 2, 3}}\nGlb = {}\nyes.\n\n\n\n", see_also : [`:: / 2, lub / 2, set_range / 3]]).
:- comment(in / 2, [summary : "E belongs to the set term Sterm.\n\n", template : "?E in ?Sterm", desc : html("   This constraint states that E belongs to the set term Sterm.  If E is\n   not a known value the constraint is delayed.  It is activated as soon as\n   E becomes a known value.  If Sterm is a ground set and E is known it\n   checks if E belongs to Sterm.\n\n<P>\n"), args : ["?E" : "A Prolog term.", "?Sterm" : "A set term."], resat : "   No.", fail_if : "   Fails if E cannot belong to Sterm.\n\n", eg : "\n[eclipse 4]: S `:: {}.. {1,2,3}, E in S.\n\nE = E\nS = S{{} .. {1, 2, 3}}\n\nDelayed goals:\n        E in_s S{{} .. {1, 2, 3}}\nyes.\n\n[eclipse 5]: S `:: {}.. {1,2,3}, 1 in S.\n\nS = S{{1} .. {1, 2, 3}}\nyes.\n\n\n\n", see_also : [`:: / 2, notin / 2]]).
:- comment(list2set / 2, [summary : "Transforms a ground list List into a ground set Svar.\n\n", template : "list2set(+List, ?Svar)", desc : html("   This predicate forces Svar to be the ground set associated with the\n   ground list List.  Svar can be a free variable or a ground set.\n\n<P>\n"), args : ["+List" : "A ground list.", "?Svar" : "A free variable or a ground set."], resat : "   No.", fail_if : "   Fails if List is not ground or if Svar is ground and different from the\n   computed set.\n\n", eg : "\n[eclipse 5]: L = [1,3,2,6,4], list2set(L, S).\n\nL = [1, 3, 2, 6, 4]\nS = {1, 2, 3, 4, 6}\nyes.\n\n\n\n", see_also : [set2list / 2]]).
:- comment(lub / 2, [summary : "S is a set domain variable and Lub is the lower bound of its domain.\n\n", template : "lub(?S, ?Lub)", desc : html("   Lub is the ground set corresponding to the upper bound of the domain of\n   S. If Lub is a free variable, it is instanciated to the upper bound of\n   the domain of S. If it is a ground set, it should be equal to the upper\n   bound of the domain of S, otherwise it fails.\n\n<P>\n"), args : ["?S" : "A set domain variable.", "?Lub" : "A free variable or a ground set."], resat : "   No.", fail_if : "   Fails if S is not a set domain variable or if Lub is a ground set not\n   equal to the upper bound of S domain.\n\n", eg : "\n[eclipse 9]: S `:: {}.. {1,2,3,5}, lub(S,Lub).\n\nS = S{{} .. {1, 2, 3}}\nLub = {1, 2, 3}\nyes.\n\n\n\n", see_also : [`:: / 2, glb / 2, set_range / 3]]).
:- comment(max_weight / 2, [summary : "Svar is a weighted set domain variable whose maximal possible weight\nattached to an element is Var.\n\n", template : "max_weight(?Svar, ?Var)", desc : html("   If Svar is a weighted set domain variable, it returns the element of its\n   domain which belongs to the set resulting from the difference of the\n   upper bound and the lower bound and which has the greatest weight.  If\n   Svar is a ground set, it just returns the element with the geratest\n   weight.\n\n<P>\n"), args : ["?Svar" : "A weighted set domain variable or a weighted set.", "?Var" : "Term unifying with a term of the form e(_,_)."], resat : "   No.", fail_if : "   Fails if Svar is not a weighted set term, or if Var can not be unified\n   with the extracted element.\n\n", eg : "\n[eclipse 4]: S `:: {e(a,10), e(b,15)} ..{e(a,10), e(b,15),\n e(c,20)},  max_weight(S,W).\n\nS = S{{e(a, 10), e(b, 15)} .. {e(a, 10), e(b, 15), e(c, 20)}}\nW = e(c, 20)\nyes.\n\n\n\n", see_also : [`:: / 2]]).
:- comment(modify_bound / 3, [summary : "Flag is a flag which takes its value in fglb, lubg.  It indicates the bound\nof the set domain variable Svar which should be updated and take the value\nVar which is ground.\n\n", template : "modify_bound(+Flag, ?Svar, +Var)", desc : html("   Flag is a flag which should take the value glb or lub, otherwise it\n   fails.  If Svar is a ground set, it succeeds if we have Var equals to\n   Svar.  If Svar is a set domain variable, its new lower or upper bound\n   will be updated and take the value Var.  For monotonicity reasons, set\n   domains can only get reduced.  So a new upper bound has to be contained\n   in the old one and a new lower bound has to contain the old one.\n   otherwise it fails.\n\n<P>\n"), args : ["+Flag" : "A ground value from fglb, lubg.", "?Svar" : "A set domain variable.", "+Var" : "A ground set."], resat : "   No.", fail_if : "   Fails if Svar is ground and different from Var or if the new upper bound\n   is not contained in the old one or the new lower bound does not contain\n   the old one.\n\n", eg : "\n[eclipse 9]: S `:: {1,2}..{1,2,3,4,6}, modify_bound(glb, S, {1,2,3}).\n\nS = S{{1, 2, 3} .. {1, 2, 3, 4, 6}}\nyes.\n\n\n\n", see_also : [`:: / 2, glb / 2, lub / 2, set_range / 3]]).
:- comment(notin / 2, [summary : "E does not belong to the set term Sterm.\n\n", template : "?E notin ?Sterm", desc : html("   This constraint states that E does not belong to the set term Sterm.  If\n   E is not a known value the constraint is delayed.  It is activated as\n   soon as E becomes a known value.  If Sterm is a ground set and E is\n   known it checks if E does not belong to Sterm.\n\n<P>\n"), args : ["?E" : "A Prolog term.", "?Sterm" : "A set term."], resat : "   No.", fail_if : "   Fails if E belongs to Sterm.\n\n", see_also : [`:: / 2, in / 2]]).
:- comment(refine / 1, [summary : "Instanciate Svar to a value in its set domain.\n\n", template : "refine(?Svar)", desc : html("   If Svar is a set domain variable, it labels Svar to its first possible\n   value (which satisfies the constraints) by taking the largest possible\n   set of elements chosen from the smallest one to the biggest one.  If\n   there are several possible instances of Svar, it creates choice points.\n   It backtracks on the element taken.  If Svar is a ground set, nothing\n   happens.  Otherwise it fails.  If List is a possible list of set domain\n   variables occuring in the program, the simplest labeling procedure is:\n\n<P>\n<PRE>\n            labelings([]).\n            labelings([S | List]) :-\n                 refine(S),\n                 labelings(List).\n</PRE>\n"), args : ["?Svar" : "A set domain variable or a ground set."], resat : "   On the taken elements.", fail_if : "   Fails if Svar is not a set domain variable or ground set.\n\n", eg : "\n[eclipse 21]: S `:: {} ..{1,2,5,3,8}, refine(S).\n\nS = {1, 2, 3, 5, 8}     More? (;)\nyes\n\n\n\n", see_also : [`:: / 2]]).
:- comment(set / 1, [summary : "Succeeds if SVar is a ground set (not a set domain)\n\n", template : "set(?SVar)", desc : html("   This predicate is used to test if a term is a ground set, that is a set\n   variable where the domain is reduced to a singleton or a set of ground\n   values defined with the symbols fg.\n\n<P>\n"), args : ["?SVar" : "A Prolog term."], resat : "   No.", fail_if : "   Fails if SVar is not a ground set.\n\n", eg : "\n[eclipse 3]: S = {a,{f(a,g),3},c}, set(S).\n\nS = {a,{f(a,g),3},c}\nyes.\n\n\n\n", see_also : [`:: / 2, glb / 2, lub / 2, set_range / 3]]).
:- comment(set2list / 2, [summary : "Transforms a ground set Svar into a list of ordered elements List.\n\n", template : "set2list(+Svar, ?List)", desc : html("   This predicate forces List to be the list of ordered elements associated\n   to the ground set Svar.  List can be a free variable or a ground term.\n   This predicate is convenient when iterations over set elements are\n   required.\n\n<P>\n"), args : ["+Svar" : "A ground set.", "?List" : "Term unifying with a list of ground values."], resat : "   No.", fail_if : "   Fails if Svar is not ground or if List is ground and different from the\n   computed list.\n\n", eg : "\n[eclipse 3]: S = {1,4,2,6,2,7}, set2list(S, L).\n\nS = {1, 2, 4, 6, 7}\nL = [1, 2, 4, 6, 7]\nyes.\n\n\n\n", see_also : [list2set / 2]]).
:- comment(set_range / 3, [summary : "Svar is a set domain variable and Glb and Lub are the respective lower\nbound and upper bound of its domain.\n\n", template : "set_range(?Svar, ?Glb, ?Lub)", desc : html("   This predicate computes the lower bound Glb and the upper bound Lub of\n   the domain attached to the set variable Svar.  If Glb and/or Lub are\n   ground, they should be equal to the respective bounds of the domain,\n   otherwise it fails.\n\n<P>\n"), args : ["?Svar" : "A set domain variable.", "?Glb" : "A free variable or a ground set.", "?Lub" : "A free variable or a ground set."], resat : "   No.", fail_if : "   Fails if Svar is not a set domain variable or if one of the terms glb,\n   Lub, can not be unified with the respective bounds of the domain of\n   Svar.\n\n", exceptions : [4 : "Var is not a domain variable."], eg : "\n[eclipse 7]: S `:: {} .. {1,2,3}, set_range(S, Glb, Lub).\n\nS = S{{} .. {1, 2, 3}}\nGlb = {}\nLub = {1, 2, 3}\nyes.\n\n\n\n", see_also : [`:: / 2, glb / 2, lub / 2]]).
:- comment(sum_weight / 2, [summary : "Svar is a weighted set domain variable or a weighted ground set and Var a\nfree variable or a domain variable or an integer which represents the\nweight of Svar.\n\n", template : "sum_weight(?Svar, ?Var)", desc : html("   Svar is a weighted set domain variable or ground set.  Var is the weight\n   of Svar.  If Var is a free variable, this constraint is a mean to access\n   a set weight and attach it to Var.  If not, the weight of Svar is\n   constrained to be equal to Var.  The constraint is delayed and activated\n   each time a modification occurs in the domain of Svar or Var.\n   Convenient when dealing with packing problems.\n\n<P>\n"), args : ["?Svar" : "A weighted set domain variable or a weighted ground set.", "?Var" : "Term unifying with a domain variable or an integer."], resat : "   No.", fail_if : "   Fails if Svar is not a weighted set term or if Var can not represent the\n   weight of Svar.\n\n", eg : "\n[eclipse 4]: S `:: {e(a,10), e(b,15)} ..{e(a,10), e(b,15),\n                    e(c,20)}, sum_weight(S, W).\n\nS = S{{e(a, 10), e(b, 15)} .. {e(a, 10), e(b, 15), e(c, 20)}}\nW = W{[25..45]}\n\nDelayed goals:\n        weight_s(S{{e(a, 10), e(b, 15)} .. {e(a, 10),\n                   e(b, 15), e(c, 20)}}, W{[25..45]})\nyes.\n\n\n\n", see_also : [`:: / 2]]).
